package com.ybear.mvp.handler;

import android.os.Looper;
import android.os.Message;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer;

import java.lang.ref.WeakReference;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * Handler
 */
final class HandlerImpl extends android.os.Handler {
    private final Executor mPool = Executors.newFixedThreadPool( 1 );
    @Nullable
    private WeakReference<HandlerCallback> mWRCall;

    HandlerImpl(@NonNull Looper looper, @Nullable Callback call) {
        super( looper, call );
    }

    HandlerImpl(@NonNull Looper looper, @Nullable HandlerCallback call) {
        super( looper, call );
        mWRCall = new WeakReference<>( call );
    }

    @Override
    public void dispatchMessage(@NonNull Message msg) {
        super.dispatchMessage(msg);
        HandlerCallback call = getCall();
        if( call != null ) call.dispatchMessage( msg );
    }

    @Nullable
    private HandlerCallback getCall() {
        return mWRCall == null ? null : mWRCall.get();
    }

    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, boolean postResult) {
        if( postResult ) {
            return postExecuteAsync(executeCall, data -> {
                if( resultCall != null ) post( () -> resultCall.accept( data ) );
            });
        }
        return postExecuteAsync( executeCall, resultCall );
    }
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, boolean postResult) {
        if( postResult ) {
            return postExecuteAsync(executeCall, data -> {
                if( resultCall != null ) post( () -> resultCall.accept( data ) );
            });
        }
        return postExecuteAsync( executeCall, resultCall );
    }

    public <T> boolean postDelayedAsync(Callable<T> executeCall, Consumer<T> resultCall,
                                        boolean postResult, long delayMillis) {
        return postDelayed(() -> postAsync( executeCall, resultCall, postResult ), delayMillis);
    }
    public <T> boolean postDelayedAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall,
                                        boolean postResult, long delayMillis) {
        return postDelayed(() -> postAsync( executeCall, resultCall, postResult ), delayMillis);
    }

    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall,
                                 boolean postResult, long delayMillis) {
        return postDelayedAsync( executeCall, resultCall, postResult, delayMillis );
    }
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall,
                                 boolean postResult, long delayMillis) {
        return postDelayedAsync( executeCall, resultCall, postResult, delayMillis );
    }

    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall) {
        return postAsync( executeCall, resultCall, true );
    }
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall) {
        return postAsync( executeCall, resultCall, true );
    }

    public <T> boolean postDelayedAsync(Callable<T> executeCall, Consumer<T> resultCall, long delayMillis) {
        return postDelayedAsync( executeCall, resultCall, true, delayMillis );
    }
    public <T> boolean postDelayedAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, long delayMillis) {
        return postDelayedAsync( executeCall, resultCall, true, delayMillis );
    }

    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, long delayMillis) {
        return postDelayedAsync( executeCall, resultCall, delayMillis );
    }
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, long delayMillis) {
        return postDelayedAsync( executeCall, resultCall, delayMillis );
    }

    public <T> boolean postAsync(Runnable executeCall) {
        return postExecuteAsync( executeCall );
    }

    public <T> boolean postDelayedAsync(Runnable executeCall, long delayMillis) {
        return postDelayed( () -> postExecuteAsync( executeCall ), delayMillis );
    }

    public <T> boolean postAsync(Runnable executeCall, long delayMillis) {
        return postDelayedAsync( executeCall, delayMillis );
    }

    /**
     * 异步处理Handler( 通过Return返回数据)
     * @param executeCall       处理的异步内容
     * @param resultCall        返回处理的内容
     * @param <T>               数据源
     * @return                  post结果
     */
    private <T> boolean postExecuteAsync(Callable<T> executeCall, Consumer<T> resultCall) {
        if( executeCall == null && resultCall == null ) return false;
        postExecuteAsync(consumer -> {
            try {
                if( consumer == null || executeCall == null ) return;
                consumer.accept( executeCall.call() );
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, resultCall);
        return true;
    }

    /**
     * 异步处理Handler（通过回调返回数据）
     * @param executeCall       处理的异步内容
     * @param resultCall        返回处理的内容
     * @param <T>               数据源
     * @return                  post结果
     */
    private <T> boolean postExecuteAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall) {
        if( executeCall == null ) return false;
        mPool.execute(() -> {
            try {
                executeCall.accept(data -> {
                    if( resultCall != null ) resultCall.accept( data );
                });
            } catch (Exception e) {
                e.printStackTrace();
            }

        });
        return true;
    }

    private <T> boolean postExecuteAsync(Runnable executeCall) {
        if( executeCall == null ) return false;
        mPool.execute( executeCall );
        return true;
    }
}